/*
 *
 * Copyright (c) 2020 The Raptor Authors. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "raptor-lite/utils/status.h"
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#endif
#include <utility>
#include "src/utils/string.h"

namespace raptor {
Status::Status()
    : Status(0, std::string()) {}

Status::~Status() {}

Status::Status(const std::string &msg)
    : Status(-1, msg) {}

Status::Status(int err_code, const std::string &err_msg)
    : err_code_(err_code)
    , desc_(err_msg) {}

Status::Status(const Status &oth)
    : err_code_(oth.err_code_)
    , desc_(oth.desc_) {}

Status &Status::operator=(const Status &oth) {
    if (this != &oth) {
        err_code_ = oth.err_code_;
        desc_     = oth.desc_;
    }
    return *this;
}

Status::Status(Status &&other)
    : err_code_(other.err_code_) {
    desc_           = std::move(other.desc_);
    other.err_code_ = 0;
}

Status &Status::operator=(Status &&other) {
    err_code_       = other.err_code_;
    desc_           = std::move(other.desc_);
    other.err_code_ = 0;
    return *this;
}

int Status::ErrorCode() const { return err_code_; }

std::string Status::ToString() const {
    if (err_code_ == 0) {
        return std::string("No error");
    }

    char *text = nullptr;
    if (desc_.empty()) {
        raptor_asprintf(&text, "Error code is %d. No description.", err_code_);
    } else {
        raptor_asprintf(&text, "Error code is %d. %s", err_code_, desc_.c_str());
    }
    std::string rsp(text);
    free(text);
    return rsp;
}

RefCountedPtr<Status> MakeStatusFromStaticString(const char *msg) {
    return MakeRefCounted<Status>(msg);
}

RefCountedPtr<Status> MakeStatusFromPosixError(const char *api) {
    int err    = errno;
    char *text = nullptr;
    raptor_asprintf(&text, "%s: %s", api, strerror(err));
    RefCountedPtr<Status> obj = MakeRefCounted<Status>(err, text);
    free(text);
    return obj;
}

#ifdef _WIN32
RefCountedPtr<Status> MakeStatusFromWindowsError(int err, const char *api) {
    char *message = raptor_format_message(err);

    char *text = nullptr;
    raptor_asprintf(&text, "%s: %s", api, message);

    size_t valid_len = strlen(text);
    while (valid_len > 0) {
        if (text[valid_len - 1] != '\r' && text[valid_len - 1] != '\n') {
            break;
        }
        valid_len -= 1;
    }

    RefCountedPtr<Status> obj = MakeRefCounted<Status>(err, std::string(text, valid_len));
    free(message);
    free(text);
    return obj;
}
#endif

} // namespace raptor
